import beforeSend from './modules/beforeSend.js'

const getObjectType = Symbol('getObjectType');
const parseThirdOptions = Symbol('parseThirdOptions');
const goLogin = Symbol('goLogin');
const api = Symbol('api');

class CreateApi {
	constructor(store,config){
		this.$store = store;
		this.$config = config;
		this.$noTokenMsg = 'Token丢失！';
		this.$invalidTokenMsg = '登录已超时，请重新登录！';
	}
	
	/*
	 内部方法，获取object对象类型
	 */
	[getObjectType](obj){
		if (typeof obj !== 'object') {
			return null;
		} else {
			let objTypeStr = Object.prototype.toString.call(obj).toLowerCase().trim();
			objTypeStr = objTypeStr.substr(1,objTypeStr.length-2)
			let tempA = objTypeStr.split(" ");
			return tempA[1];
		}	
	}
	
	/*
	内部方法，解析额外设置
	 */
	[parseThirdOptions](opts){
		const defaultOpts = {
			warn:true,
			host:'default',
			block:'default',
			needToken:true,
			fullRes:false,
			loading:true
		}
		let result = {...defaultOpts}
		if (opts) {
			if (typeof opts === 'string') {
				result.block = opts
			} else if (this[getObjectType](opts)==='object') {
				result = {...result,...opts}
			}
		} 
		return result;
	}
	
	/*
	跳转到登录页面
	 */
	[goLogin](){
		let pages = getCurrentPages();
		if (('/'+pages[0].route)!==this.$config.path.login){
			uni.redirectTo({url:this.$config.path.login})
		}
	}
	
	/*
	api调用
	 */
	[api](httpMethod,method,params={},opts,paramsX){
		return new Promise((resolve, reject)=>{
			httpMethod = httpMethod.toUpperCase()
			let beforeRes = this.getHeaders(opts)  //获取请求头
			let headerOption = {};
			if (!beforeRes.flag) {
				//token丢失错误
				this[goLogin]()
				reject(this.$noTokenMsg);
			} else {
				headerOption = beforeRes.headers;   //请求头赋值
				let url = this.getUrl(method,opts,true);  //组成请求地址
				if (httpMethod==='POST'||httpMethod==='PUT'||httpMethod==='PATCH') {
					//POST和PUT方法，却使用GET方式传参，需要做参数处理
					let tempStr = '';
					if (this[getObjectType](paramsX)==='object') {
						let tempArr = [];
						for (let fieldName in paramsX) {
							tempArr.push(fieldName+'='+paramsX[fieldName])
						}
						tempStr = tempArr.join('&');
					}
					if (tempStr) {
						if (url.indexOf('?')<0) {
							url += '?' + tempStr;
						} else {
							url += '&' + tempStr;
						}
					}
				} else {
					//GET和DELETE方法，加时间戳
					params = {...params,...{timekey:new Date().getTime()}};
				}
				
				let ajaxOptions = {
					url:url,
					data:params,
					method:httpMethod,
					header:headerOption,
					success:(response)=>{
						if (response.header['access-token'] && response.header['access-token'] !== 'invalid_token') {
						  this.$store.commit('user/setToken',response.header['access-token'])
						}
						if (response.header['x-access-token']) {
						  this.$store.commit('user/setRefreshToken',response.header['x-access-token'])
						}
						if (response.statusCode===200) {  //请求状态为200，成功
							if (opts.host!=='default') {
								resolve(response.data);
							} else {
								if (response.data.code===401) {
									this[goLogin]()
									let eMsgA = response.data.message;
									if (!eMsgA) eMsgA = this.$invalidTokenMsg;
									reject(eMsgA);
								} else if (response.data.success===true && response.data.code===200) {
									if (!opts.fullRes) {
										resolve(response.data.data);
									} else {
										resolve(response.data);
									}
								} else {  //后端返回其它code，出错
									console.log('Ajax backstage Error, return: ',response.data)
									let eMsg = response.data.message;
									if (!eMsg) eMsg = this.$config.ajax.errMsg;
									reject(eMsg);
								}
							}
						} else {  //请求状态为非200，出错
							console.log('Ajax Error Code: '+response.statusCode)
							reject(this.$config.ajax.errMsg);
						}
					},
					fail:(err1)=>{  //api调用失败，出错
						reject(this.$config.ajax.errMsg);
					}
				}
				uni.request(ajaxOptions)
			}
		})
	}
	
	/*
	获取请求头
	  opts 请求参数，JSON对象，其中 needToken: boolean 是否需要传递token
		headers 原有的headers，JSON对象
		self 是否是内部调用，外部调用不传
	 */
	getHeaders(opts,headers,self=false){
		let res = {flag:true,headers:{}};
		if (!self) {
			opts = this[parseThirdOptions](opts)
		}
		if (headers && this[getObjectType](headers)==='object') {
			res.headers=headers;
		}
		let temp = beforeSend(opts,this.$store,res.headers)
		if (temp.flag) {
			res.headers = temp.headers;
		} else {
			res.flag = false;
		}
		return res;
	}
	
	/*
	获取请求地址
	  method 请求的后端方法名称
		opts 求参数，JSON对象，其中 host 为config中配置的域名名称， block 为 config 中配置的接口模块名称，
		self 是否是内部调用，外部调用不传
	 */
	getUrl(method,opts,self=false){
		let res = method;
		if (!self) {
			opts = this[parseThirdOptions](opts)
		}
		let host = this.$config.ajax.host[opts.host];
		let saveHost = this.$store.getters['system/getHost'];
		if (saveHost) {
			if (opts.host==='default') {
				host = saveHost;
			}
		}
		res = host + this.$config.ajax.block[opts.block] + res;
		return res;
	}
	
	/* 
	 httpMethod: get post put dellete patch
	 method:接口方法名
	 params:传递给后端的数据（JSON）
	 opts:接口调用方法额外设置
	 paramsX：post put时，如果需要url后面带的其他参数，JSON格式
	 */
	base(httpMethod,method,params={},opts,paramsX){
		opts = this[parseThirdOptions](opts)
		if (opts.loading) {
			uni.showLoading({
				title: '加载中...',
				mask:true
			});
		}
		return new Promise((resolve, reject)=>{
			this[api](httpMethod,method,params,opts,paramsX).then((d)=>{
				if (opts.loading) {
					uni.hideLoading();
				}
				resolve(d)
			}).catch(err=>{
				if (opts.loading) {
					uni.hideLoading();
				}
				if (typeof err !== 'string') {
					err = this.$config.ajax.errMsg;
				}
				if (opts.warn) {
					setTimeout(()=>{
						uni.showModal({
							title:'系统提示',
							content:err,
							showCancel:false
						})
					},100)
				}
				reject(err)
			})
		})
	}
}

CreateApi.prototype.get = function(method,params,opts){
	return this.base('GET',method,params,opts,{})
}
CreateApi.prototype.post = function(method,params,opts,paramsX){
	return this.base('POST',method,params,opts,paramsX)
}
CreateApi.prototype.put = function(method,params,opts,paramsX){
	return this.base('PUT',method,params,opts,paramsX)
}
CreateApi.prototype.delete = function(method,params,opts){
	return this.base('DELETE',method,params,opts,{})
}
CreateApi.prototype.patch = function(method,params,opts,paramsX){
	return this.base('PATCH',method,params,opts,paramsX)
}

export default CreateApi